package com.vxdata.utils.modules.utils.security;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.CronExpression;
import org.quartz.TriggerUtils;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.scheduling.support.CronSequenceGenerator;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

/**
 * 获取Cron表达式最近几次执行的时间
 */
@Slf4j
public class CronNextExecUtil {

    public void getTime() {
        String cronExpress = "0 */30 * * * ?";//此处为cron表达式
        cronExpress = "0 0/30 * * * ?";
        try {
            CronExpression cronExpression = new CronExpression(cronExpress);//导包import org.quartz.CronExpression;
            Date date = cronExpression.getTimeAfter(new Date());
            //将date转换为指定日期格式字符串
            SimpleDateFormat dataFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String dateString = dataFormat.format(date);
            //dateString为转换后的日期格式
            log.info("{} {}", cronExpress, dateString);
        } catch (Exception e) {
            log.error("cron获取下次执行时间异常" + e);
        }
    }

    /**
     * 列出近cronCount次的执行时间
     *
     * @param cronExpression cron表达式
     * @param cronCount      cron时间次数
     * @param maxCronCount   最大cron时间次数
     * @return
     */
    public static List<String> listCronRunTime(String cronExpression, Integer cronCount, Integer maxCronCount) {
        if (StringUtils.isBlank(cronExpression)) {
            throw new RuntimeException("Cron 表达式不能为空!");
        }
        if (!CronSequenceGenerator.isValidExpression(cronExpression)) {
            throw new RuntimeException("Cron格式不正确,Cron: " + cronExpression);
        }
        if (cronCount < 1) {
            cronCount = 1;
        }
        if (maxCronCount < 1) {
            maxCronCount = 100;
        }
        if (cronCount > maxCronCount) {
            cronCount = maxCronCount;
        }
        CronSequenceGenerator cronSequenceGenerator = new CronSequenceGenerator(cronExpression);
        List<String> cronTimeList = new ArrayList<>();
        Date nextTimePoint = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (int i = 0; i < cronCount; i++) {
            nextTimePoint = cronSequenceGenerator.next(nextTimePoint);
            cronTimeList.add(sdf.format(nextTimePoint));
        }
        return cronTimeList;
    }

    /**
     * 列出近numTimes次的执行时间
     *
     * @param cronExpression cron表达式
     * @param numTimes       下几次运行时间
     * @return
     */
    public static List<String> getNextExecTime(String cronExpression, Integer numTimes) {
        List<String> list = new ArrayList<>();
        CronTriggerImpl cronTriggerImpl = new CronTriggerImpl();
        try {
            cronTriggerImpl.setCronExpression(cronExpression);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        // 这个是重点，一行代码搞定
        List<Date> dates = TriggerUtils.computeFireTimes(cronTriggerImpl, null, numTimes);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (Date date : dates) {
            list.add(dateFormat.format(date));
        }
        return list;
    }

    /**
     * Java8 通过foreach 遍历List，同时输出下标
     * 利用BiConsumer实现foreach循环支持index
     *
     * @param biConsumer
     * @param <T>
     * @return
     */
    public static <T> Consumer<T> forEachWithIndex(BiConsumer<T, Integer> biConsumer) {
        /*这里说明一下，我们每次传入forEach都是一个重新实例化的Consumer对象，在lambada表达式中我们无法对int进行++操作,
        我们模拟AtomicInteger对象，写个getAndIncrement方法，不能直接使用AtomicInteger哦*/
        class IncrementInt {
            int i = 0;

            public int getAndIncrement() {
                return i++;
            }
        }
        IncrementInt incrementInt = new IncrementInt();
        return t -> biConsumer.accept(t, incrementInt.getAndIncrement());
    }

    public static void main(String[] args) {
        CronNextExecUtil cronUtil = new CronNextExecUtil();
        cronUtil.getTime();


        String cron = "0 0/30 * * * ?"; // 0 0/30 * * * ? 每隔30分钟执行一次 同 0 */30 * * * ?
        cron = "0 0/5 14 * * ?"; // 0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发
        log.info("cron: {}", cron);
        List<String> timeList = listCronRunTime(cron, 10, 100);
        timeList.stream().forEach(forEachWithIndex((item, index) -> {
            log.info("{} {}", index + 1, item);
        }));

        List<String> time2List = getNextExecTime(cron, 10);
        time2List.stream().forEach(x -> {
            log.info("---- {}", x);
        });
    }
}
